#include <assert.h>
#include <stdio.h>
#include <stdlib.h>

#include "../src/estep.c"

typedef struct _EstepTestDatum EstepTestDatum ;
struct _EstepTestDatum 
{ 
  struct
    {
      double    priorz[5];
      Rating    ratings[8];
      double    logalpha[3];
      double    tau[4*(5-1)];
      double    loglambda[4];
      int       clamp[3];
    }                   inputs;

  double pz[3*5];
};

static void
test_estep (void)
{
  EstepTestDatum data[] = 
    {{{{0.254248, 0.557839, 0.697463, 0.987273,  0.0509729}, {{1, 0, 3}, {3, 1, 4}, {0, 2, 1}, {0, 0, 2}, {2, 2,  4}, {0, 1, 2}, {3, 2, 1}, {1, 0, 4}}, {0.328473, 0.718952,  0.863915}, {0.156609, 0.0398387, 0.0726021, 0.506724, 0.0269233,  0.839646, 0.0945199, 0.475126, 0.644241, 0.40361, 0.900314,  0.149032, 0.128496, 0.362218, 0.191028, 0.38516}, {0.874248,  0.804379, 0.493565, 0.397887}, {1, -1, 0}}, {7.16154e-8, 1.,  2.49431e-10, 1.46956e-14, 8.46599e-19, 0.676421, 0.323552,  0.0000272281, 2.07109e-9, 5.70491e-15, 1., 9.91008e-11,  1.21863e-22, 1.19356e-34,  1.16424e-46}}, {{{0.533972, 0.666666, 0.436067, 0.702011,  0.0272478}, {{0, 2, 4}, {2, 1, 2}, {1, 2, 4}, {3, 2, 1}, {2, 2,  3}, {0, 2, 3}, {2, 2, 1}, {2, 2, 1}}, {0.639743, 0.596421,  0.607491}, {0.552122, 0.995502, 0.192811, 0.707177, 0.403089,  0.867006, 0.830593, 0.516149, 0.0179293, 0.992757, 0.0262147,  0.0225845, 0.620043, 0.169482, 0.550309, 0.247972}, {0.0860708,  0.502816, 0.114242, 0.545961}, {-1, 2, 1}}, {0.225689, 0.281774,  0.184308, 0.296712, 0.0115166, 0.000434133, 0.000126692, 0.999439,  4.3317e-8, 7.40742e-10, 1.7998e-8, 1., 9.86049e-17,  6.6308e-28,  3.78095e-39}}, {{{0.93847, 0.506701, 0.867571, 0.32501,  0.231293}, {{3, 2, 1}, {0, 0, 1}, {0, 0, 4}, {2, 2, 1}, {2, 2,  2}, {1, 2, 0}, {0, 2, 1}, {0, 0, 1}}, {0.103612, 0.000565102,  0.494416}, {0.715144, 0.0856825, 0.00780763, 0.468202, 0.69256,  0.46564, 0.838326, 0.917893, 0.444588, 0.379569, 0.33551,  0.803651, 0.898627, 0.320746, 0.472437, 0.28583}, {0.960157,  0.814045, 0.604866, 0.96082}, {2, 3, 3}}, {0.997506, 0.00244434,  0.0000492443, 3.59085e-18, 1.01483e-25, 2.5e-6, 2.5e-6,  2.5e-6, 0.99999, 2.5e-6, 1., 1.9176e-9, 9.60487e-33,  3.20113e-51,  6.22462e-81}}, {{{0.466404, 0.0137199, 0.62475, 0.596493,  0.998202}, {{3, 0, 1}, {3, 2, 3}, {2, 2, 2}, {2, 2, 2}, {0, 0,  0}, {2, 2, 3}, {2, 1, 4}, {3, 1, 1}}, {0.32116, 0.159111,  0.758168}, {0.0803098, 0.876573, 0.779541, 0.422658, 0.276659,  0.977946, 0.458795, 0.950221, 0.99083, 0.0177887, 0.644751,  0.345355, 0.0300095, 0.288925, 0.934318, 0.741054}, {0.563606,  0.275205, 0.309567, 0.14456}, {2, 0, -1}}, {0.994578, 0.0032681,  0.00215438, 3.22928e-15, 1.72081e-21, 0.999984, 0.000015584,  8.7596e-7, 1.87373e-8, 3.37606e-10, 0.14617, 0.853825,  5.38916e-6, 2.25362e-13,  1.55276e-20}}, {{{0.386392, 0.485094, 0.0774719, 0.370915,  0.963734}, {{3, 1, 3}, {1, 1, 4}, {0, 0, 1}, {1, 1, 1}, {0, 1,  1}, {3, 1, 4}, {0, 1, 2}, {2, 0, 4}}, {0.208434, 0.0995264,  0.91212}, {0.0135133, 0.217605, 0.0817377, 0.267369, 0.668159,  0.187595, 0.792813, 0.333052, 0.927105, 0.62399, 0.517608,  0.0234843, 0.782545, 0.0585863, 0.563564, 0.873028}, {0.396152,  0.573493, 0.486092, 0.502112}, {-1, -1, -1}}, {0.275993, 0.723256,  0.000735846, 0.0000153105, 1.65265e-7, 0.0295927, 0.970407,  2.68683e-7, 2.31434e-13, 7.85105e-20, 0.169203, 0.212424,  0.0339252, 0.162425,  0.422023}}, {{{0.589993, 0.418905, 0.147454, 0.304828,  0.322623}, {{2, 2, 1}, {0, 1, 2}, {2, 1, 1}, {0, 0, 1}, {3, 0,  1}, {3, 1, 1}, {3, 2, 2}, {1, 0, 3}}, {0.750746, 0.959858,  0.512015}, {0.989572, 0.823641, 0.335869, 0.994407, 0.966088,  0.0410967, 0.277282, 0.430843, 0.09306, 0.644945, 0.70379,  0.944751, 0.590948, 0.212527, 0.338731, 0.558186}, {0.000955163,  0.793622, 0.191278, 0.253359}, {0, -1, -1}}, {0.999999,  1.20794e-6, 1.73754e-14, 8.67715e-23, 3.89552e-31,  0.990752, 0.00924845, 3.32659e-13, 1.29056e-23,  2.31864e-34, 0.917857, 0.0821396, 3.10823e-6, 2.35006e-10,  8.01764e-15}}, {{{0.741344, 0.68876, 0.219235, 0.895551,  0.746937}, {{1, 2, 2}, {2, 2, 0}, {2, 1, 2}, {3, 1, 0}, {0, 0,  3}, {0, 1, 0}, {3, 2, 0}, {2, 2, 0}}, {0.722672, 0.178138,  0.618268}, {0.316094, 0.629612, 0.533194, 0.914479, 0.371343,  0.0386648, 0.320667, 0.575747, 0.813157, 0.0377096, 0.527045,  0.38447, 0.559798, 0.359378, 0.484169, 0.15305}, {0.818454,  0.670618, 0.264934, 0.257499}, {-1, 4, -1}}, {0.00226145,  0.992357, 0.00518023, 0.00019959, 1.56052e-6, 0.999802,  0.0001977, 1.47326e-12, 3.13397e-21, 2.31891e-24, 1.,  6.58767e-9, 9.27506e-25, 7.52244e-40,  1.18553e-55}}, {{{0.639231, 0.755423, 0.318333, 0.553602,  0.724752}, {{0, 1, 3}, {0, 0, 1}, {2, 2, 2}, {0, 1, 4}, {3, 1,  0}, {3, 0, 0}, {3, 1, 3}, {2, 0, 4}}, {0.38408, 0.279668,  0.232934}, {0.149005, 0.570923, 0.241959, 0.705889, 0.764535,  0.0111249, 0.882581, 0.221721, 0.611485, 0.192671, 0.211963,  0.956787, 0.353986, 0.121154, 0.264018, 0.869991}, {0.714755,  0.365731, 0.945685, 0.31639}, {0, 1, 0}}, {0.999999,  5.30221e-7, 9.90516e-14, 4.37331e-21, 1.72642e-28,  6.15008e-8, 1., 1.38423e-10, 1.38617e-15, 1.10546e-20,  0.999999, 1.47188e-6, 4.15858e-9, 6.45655e-12,  9.72149e-15}}, {{{0.0834552, 0.840998, 0.410729, 0.424058,  0.377566}, {{2, 0, 4}, {1, 0, 3}, {0, 1, 1}, {3, 0, 4}, {2, 1,  4}, {2, 0, 2}, {0, 2, 2}, {2, 1, 3}}, {0.0764627, 0.399604,  0.541477}, {0.155845, 0.464978, 0.206933, 0.329514, 0.199058,  0.110992, 0.0857792, 0.0654968, 0.329067, 0.396237, 0.720048,  0.119812, 0.0126773, 0.406234, 0.738396, 0.453795}, {0.929222,  0.565237, 0.327668, 0.0297374}, {3, -1, 2}}, {0.0000932012,  0.00761633, 0.00025189, 0.992039, 1.98325e-8, 0.287287,  0.712713, 9.0281e-7, 1.47096e-12, 1.995e-18, 0.265899,  0.0103408, 0.723761, 3.00259e-10,  4.9792e-14}}, {{{0.48826, 0.395811, 0.0237961, 0.721131,  0.158746}, {{1, 0, 1}, {0, 2, 3}, {1, 2, 3}, {2, 0, 2}, {2, 2,  2}, {0, 2, 4}, {1, 2, 2}, {2, 0, 0}}, {0.196753, 0.912804,  0.635352}, {0.0932487, 0.867686, 0.516567, 0.915304, 0.973437,  0.855009, 0.110332, 0.176907, 0.519641, 0.925787, 0.545096,  0.84924, 0.489904, 0.37413, 0.0563221, 0.921176}, {0.00164373,  0.978319, 0.0325259, 0.200045}, {4, 0, -1}}, {0.986513, 0.0134871,  2.44239e-9, 1.12426e-16, 1.58055e-18, 0.99999, 2.5e-6,  2.5e-6, 2.5e-6, 2.5e-6, 9.6046e-7, 0.999999,  5.75876e-10, 2.08818e-17, 4.22037e-27}}};

  for (unsigned int i = 0; i < sizeof (data) / sizeof (data[0]); ++i)
    {
      double pz[3*5];

      for (unsigned int j = 0; j < 3*5; ++j) { pz[j] = drand48 (); }

      estep (data[i].inputs.logalpha,
             5,
             data[i].inputs.tau,
             3,
             data[i].inputs.loglambda,
             pz,
             data[i].inputs.priorz,
             data[i].inputs.clamp,
             data[i].inputs.ratings,
             8);

      for (unsigned int j = 0; j < 3*5; ++j)
        {
          assert (fabs (pz[j] - data[i].pz[j]) <=
                  1e-4 * (1 + fabs (pz[j]) + fabs (data[i].pz[j])) ||
                  (fprintf (stderr, "%u: %g ?= %g\n", j, pz[j], data[i].pz[j]), 0));
        }
    }
}

int 
main (void)
{
  srand48 (69);

  test_estep ();

  return 0;
}
